package thread;

import lombok.Data;

import javax.naming.Name;
import java.math.BigDecimal;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @author ycz
 * @date 2021/5/31
 * @description https://www.cnblogs.com/myseries/p/11575757.html
 * 保证线程执行顺序
 *
 */
@Data
public class ThreadTest {


    public static void main(String[] args) throws Exception {
        Thread thread1 = new Thread(() -> System.out.println("1"));
        Thread thread2 = new Thread(() -> System.out.println("2"));
        Thread thread3 = new Thread(() -> System.out.println("3"));
        thread1.start();
        thread2.start();
        thread3.start();

        // join() 让父线程等待子线程结束之后才能继续运行
        // 将线程串行化
//        join();
        // 单例线程池
//        singleThreadPool();

        //
        bySephmore();

    }

    public static void join() throws Exception {
        Thread.sleep(100);
        System.out.println("======join()保证线程执行顺序=======");
        Thread thread1 = new Thread(() -> System.out.println("1"));
        Thread thread2 = new Thread(() -> System.out.println("2"));
        Thread thread3 = new Thread(() -> System.out.println("3"));
        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();
        thread3.start();
    }

    public static void singleThreadPool() throws InterruptedException {
        Thread.sleep(100);
        System.out.println("======单例线程池保证线程执行顺序=======");
        Thread thread1 = new Thread(() -> System.out.println("1"));
        Thread thread2 = new Thread(() -> System.out.println("2"));
        Thread thread3 = new Thread(() -> System.out.println("3"));
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(thread1);
        executorService.submit(thread2);
        executorService.submit(thread3);
    }


    //信号量
    static volatile int ticket = 1;
    //线程休眠时间
    public final static int SLEEP_TIME = 1;

    public static void foo(int name) {
        //因为线程的执行顺序是不可预期的，因此需要每个线程自旋
        while (true) {
            if (ticket == name) {
                try {
                    Thread.sleep(SLEEP_TIME);
                    //每个线程循环打印3次
                    for (int i = 0; i < 3; i++) {
                        System.out.println(name + " " + i);
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //信号量变更
                ticket = name % 3 + 1;
                return;

            }
        }
    }

    public static void byVolatileAnd() throws InterruptedException {
        Thread.sleep(100);
        System.out.println("======使用volatile关键字修饰的信号量实现=======");
        Thread thread1 = new Thread(() -> foo(1));
        Thread thread2 = new Thread(() -> foo(2));
        Thread thread3 = new Thread(() -> foo(3));
        thread1.start();
        thread2.start();
        thread3.start();
    }

    /**
     * 使用Sephmore(信号量)实现线程按顺序运行
     */
    public static void bySephmore() throws Exception {
        Thread.sleep(100);
        System.out.println("======使用Sephmore(信号量)实现线程按顺序运行=======");
        Semaphore semaphore1 = new Semaphore(1);
        Semaphore semaphore2 = new Semaphore(1);
        Thread thread1 = new Thread(() -> {
            System.out.println(1);
            semaphore1.release();
        });
        Thread thread2 = new Thread(() -> {
            try {
                semaphore1.acquire();
                System.out.println(2);
                semaphore2.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread thread3 = new Thread(() -> {
            try {
                semaphore2.acquire();
                thread2.join();
                System.out.println(3);
                semaphore2.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }

}
